import * as babelParser from '@babel/parser';
import { isFunctionDeclaration, isExportDefaultDeclaration, isObjectExpression, Node, isIdentifier, isObjectMethod } from '@babel/types';

import { getFunctionName } from './utils';
import { parseCommentForFunction } from '../../comment';
import { readFileContent, getFileExt, isNotEmptyObject } from '../../utils';

import { IScriptParseResult } from '../../types/script';

export default parseScript;

/**
 * 解析 Script
 */
function parseScript(filepath: string) {
    const ext = getFileExt(filepath);
    const fileType = ext === 'js' ? 'javascript' : ext === 'ts' ? 'typescript' : ext;

    if (fileType === 'javascript' || fileType === 'typescript') {
        // ...
        const code = readFileContent(filepath);
        if (code) {
            const parseResult: IScriptParseResult = { type: fileType };

            if (parseResult.type === 'javascript') {
                const functions = parseJavascript(code);
                if (functions) parseResult.functions = functions;
            } else if (parseResult.type === 'typescript') {
                const functions = parseTypescript(code);
                if (functions) parseResult.functions = functions;
            }

            return parseResult as IScriptParseResult;
        }

        // ...
    } else {
        throw new Error('仅支持 JS/TS 文件');
    }
}

/**
 * 解析 Javascript
 */
function parseJavascript(code: string) {
    const ast = babelParser.parse(code, {
        sourceType: 'module'
    });
    const program = ast.program;
    const body = program.body;

    const functions: IScriptParseResult['functions'] = {};

    const parseMethod = (node: Node) => {
        const name = getFunctionName(node);
        functions[name] = {};

        if (node.leadingComments) {
            for (const comment of node.leadingComments) {
                const info = parseCommentForFunction(comment);
                Object.assign(functions[name], info);
            }
        }

        // 如果注释没有说明参数
        // 则从函数中读取参数
        // @ts-ignore
        if (!functions[name].params && node.params) {
            functions[name].params = [];
            // @ts-ignore
            for (const param of node.params) {
                if (isIdentifier(param)) {
                    functions[name].params?.push({
                        name: param.name
                    });
                }
            }
            if (!functions[name].params?.length) delete functions[name].params;
        }
    };

    // 解析多种函数定义情况
    // 1. 未导出的函数
    // 2. 导出的函数
    // 3. 默认导出的函数（可能没有函数名）
    // 4. 默认导出的对象中挂载函数
    for (const node of body) {
        if (isFunctionDeclaration(node)) {
            parseMethod(node);
        } else if (isExportDefaultDeclaration(node)) {
            if (isObjectExpression(node.declaration)) {
                for (const method of node.declaration.properties) {
                    // @ts-ignore
                    if (method.method) {
                        parseMethod(method);
                    }
                }
            } else if (isFunctionDeclaration(node.declaration)) {
                parseMethod(node);
            }
        }
    }

    if (isNotEmptyObject(functions)) return functions;
}

/**
 * 解析 Typescript
 */
function parseTypescript(code: string) {
    const ast = babelParser.parse(code, {
        sourceType: 'module'
    });

    const functions: IScriptParseResult['functions'] = {};

    if (Object.keys(functions).length) return functions;
}
